#include "../Channel.h"
#include "../EventLoop.h"
using namespace yhaida;

const int Channel::kNoneEvent = 0;
const int Channel::kReadEvent = POLLIN | POLLPRI;
const int Channel::kWriteEvent = POLLOUT;

Channel::Channel(EventLoop *loop, int fd)
    : _mainEventLoop(loop),
      _fd(fd),
      _events(0),
      _revents(0),
      _index(-1),
      _isEventHandle(false)
{
}
Channel::~Channel()
{
    assert(!_isEventHandle);
}
void Channel::handleEvent(Timestamp receiveTime)
{
    // POLLIN: 有普通数据或者优先数据可读
    // POLLPRI: 有紧急数据可读
    // POLLOUT: 有普通数据可写
    // POLLERR: 有错误发生
    // POLLNVAL: 描述符非法
    // POLLRDHUP: Stream socket的一端关闭了连接或者是写端关闭了连接，如果要使用这个事件.

    // POLLRDNORM: 有普通数据可读
    // POLLRDBAND: 有优先数据可读
    // POLLWRNORM: 有普通数据可写
    // POLLWRBAND: 有紧急数据可写
    // POLLHUP: 有描述符挂起事件发生
    assert(!_isEventHandle);
    _isEventHandle = true;

    // 单纯POLLHUP是可读的，但是POLLHUP且！POLLIN说明客户端断开连接
    // 可以用POLLRDHUP代替_revents & POLLHUP && !(_revents & POLLIN)
    if(_revents & POLLHUP && !(_revents & POLLIN) )
    {
        //文件描述符挂起，并且不是读事件
        //POLLHUP 描述符挂起，比如管道的写端被关闭后，读端描述符将收到此事件
        if(_closeCallBackFunc)
        {
            LOG_WARN << "Channel::handle_event() POLLHUP";
            _closeCallBackFunc();
        }
    }

    if (_revents & POLLNVAL)
    {
        LOG_WARN << "channel::handle_event() POLLNVAL";
    }

    if (_revents & (POLLERR | POLLNVAL))
    {
        if (_errorCallBackFunc)
        {
            _errorCallBackFunc();
        }
    }

    if (_revents & (POLLIN | POLLPRI | POLLRDHUP))
    {
        if (_readCallBackFunc)
        {
            LOG_TRACE << "Channel::handle_event() fd = " << _fd<< " READ";
            _readCallBackFunc(receiveTime);
        }
    }

    if (_revents & (POLLOUT))
    {
        if (_writeCallBackFunc)
        {
            LOG_TRACE << "Channel::handle_event() fd = " << _fd<< " WRITE";
            _writeCallBackFunc();
        }
    }
    _isEventHandle = false;

}
//比如回调函数改变了，需要将EventLoop里面的channel链表重新更新
void Channel::update()
{
    _mainEventLoop->ChannelUpDate(this);
}